package org.ehe.business.engineer.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.ehe.business.engineer.domain.EngineerEntity;
import org.ehe.business.engineer.domain.EngineerLevelConfigEntity;
import org.ehe.business.engineer.domain.QuarterlyScoreEntity;
import org.ehe.business.engineer.mapper.EngineerLevelConfigMapper;
import org.ehe.business.engineer.mapper.EngineerMapper;
import org.ehe.business.engineer.mapper.QuarterlyScoreMapper;
import org.ehe.business.engineer.service.QuarterlyScoreService;
import org.ehe.business.engineer.domain.LevelChangeRecordEntity;
import org.ehe.business.engineer.mapper.LevelChangeRecordMapper;
import org.ehe.business.project.domain.ProjectAssignmentEntity;
import org.ehe.business.project.domain.ProjectEntity;
import org.ehe.business.project.domain.dto.CompleteProjectRequest;
import org.ehe.business.project.mapper.ProjectAssignmentMapper;
import org.ehe.business.project.mapper.ProjectMapper;
import org.ehe.common.core.constant.ProjectConstants;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.List;


/**
 * @author :zhangnn
 * @className :QuarterlyScoreServiceImpl
 * @description: 评分服务
 * @date 2025-07-16 10:54:09
 */
@Service
@RequiredArgsConstructor
public class QuarterlyScoreServiceImpl extends ServiceImpl<QuarterlyScoreMapper, QuarterlyScoreEntity> implements QuarterlyScoreService {
    private final ProjectAssignmentMapper assignmentMapper;
    private final EngineerMapper engineerMapper;
    private final EngineerLevelConfigMapper levelConfigMapper;
    private final LevelChangeRecordMapper levelChangeMapper;
    private final QuarterlyScoreMapper quarterlyScoreMapper;
    private final ProjectMapper projectMapper;

    /**
     * 完成项目并计算评分
     */
    @Transactional
    public void completeProject(CompleteProjectRequest request) {
        ProjectAssignmentEntity assignment = assignmentMapper.selectById(request.getAssignmentId());
        if (assignment == null) {
            throw new RuntimeException("项目分配不存在");
        }

        // 计算实际天数
        long actualDays = ChronoUnit.DAYS.between(assignment.getAssignmentDate(), request.getCompletionDateTime());
        assignment.setActualDays((int) actualDays);
        assignment.setCompletionDate(request.getCompletionDateTime());
        assignment.setStatus(request.getStatus());
        assignment.setTestPassed(request.getTestPassed());

        // 计算评分
        BigDecimal score = calculateProjectScore(assignment);
        assignment.setTotalScore(score);

        // 更新项目分配
        assignmentMapper.updateById(assignment);

        // 检查是否触发即时升级
        checkImmediatePromotion(assignment);
    }

    /**
     * 计算项目评分
     */
    private BigDecimal calculateProjectScore(ProjectAssignmentEntity assignment) {
        EngineerEntity engineer = engineerMapper.selectById(assignment.getEngineerId());

        // 1. 时效分（40%）
        BigDecimal timelinessScore = calculateTimelinessScore(assignment);
        assignment.setTimelinessScore(timelinessScore);

        // 2. 难度分（30%）
        BigDecimal difficultyScore = calculateDifficultyScore(assignment, engineer);
        assignment.setDifficultyScore(difficultyScore);

        // 3. 成功率分（30%）
        BigDecimal successScore = calculateSuccessScore(assignment);
        assignment.setSuccessScore(successScore);

        return timelinessScore.add(difficultyScore).add(successScore);
    }

    /**
     * 计算时效分
     */
    private BigDecimal calculateTimelinessScore(ProjectAssignmentEntity assignment) {
        int plannedDays = assignment.getPlannedDays();
        int actualDays = assignment.getActualDays();

        if (actualDays <= plannedDays) {
            return BigDecimal.valueOf(40);
        }

        // 每超1天扣 40/T0 分
        int overDays = actualDays - plannedDays;
        BigDecimal deduction = BigDecimal.valueOf(40).divide(BigDecimal.valueOf(plannedDays), 2, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(overDays));

        BigDecimal score = BigDecimal.valueOf(40).subtract(deduction);
        return score.max(BigDecimal.ZERO);
    }

    /**
     * 计算难度分
     */
    private BigDecimal calculateDifficultyScore(ProjectAssignmentEntity assignment, EngineerEntity engineer) {
        // 获取项目难度分
        QueryWrapper<ProjectEntity> projectWrapper = new QueryWrapper<>();
        projectWrapper.eq("id", assignment.getProjectId());
        ProjectEntity project =  projectMapper.selectOne(projectWrapper);

        // 获取工程师职级配置
        QueryWrapper<EngineerLevelConfigEntity> levelWrapper = new QueryWrapper<>();
        levelWrapper.eq("level", engineer.getCurrentLevel());
        EngineerLevelConfigEntity levelConfig = levelConfigMapper.selectOne(levelWrapper);

        int projectDifficulty = project.getDifficultyScore();
        int maxDifficulty = levelConfig.getMaxDifficultyScore();

        // 如果项目难度超过职级上限，说明是越级项目
        if (projectDifficulty > maxDifficulty) {
            return BigDecimal.valueOf(30); // 越级项目给满分
        }

        return BigDecimal.valueOf(maxDifficulty);
    }

    /**
     * 计算成功率分
     */
    private BigDecimal calculateSuccessScore(ProjectAssignmentEntity assignment) {
        return assignment.getTestPassed() == 1 ? BigDecimal.valueOf(30) : BigDecimal.ZERO;
    }

    /**
     * 检查即时升级
     */
    private void checkImmediatePromotion(ProjectAssignmentEntity assignment) {
        if (assignment.getTotalScore().compareTo(BigDecimal.valueOf(90)) >= 0) {
            EngineerEntity engineer = engineerMapper.selectById(assignment.getEngineerId());

            // 检查是否为越级项目
            if (isOverLevelProject(assignment, engineer)) {
                promoteEngineer(engineer, assignment);
            }
        }
    }

    /**
     * 判断是否为越级项目
     */
    private boolean isOverLevelProject(ProjectAssignmentEntity assignment, EngineerEntity engineer) {
        QueryWrapper<ProjectEntity> projectWrapper = new QueryWrapper<>();
        projectWrapper.eq("id", assignment.getProjectId());
        ProjectEntity project = projectMapper.selectOne(projectWrapper);

        QueryWrapper<EngineerLevelConfigEntity> levelWrapper = new QueryWrapper<>();
        levelWrapper.eq("level", engineer.getCurrentLevel());
        EngineerLevelConfigEntity levelConfig = levelConfigMapper.selectOne(levelWrapper);

        return project.getDifficultyScore() > levelConfig.getMaxDifficultyScore();
    }

    /**
     * 升级工程师
     */
    private void promoteEngineer(EngineerEntity engineer, ProjectAssignmentEntity assignment) {
        String oldLevel = engineer.getCurrentLevel();
        String newLevel = getNextLevel(oldLevel);

        if (newLevel == null) {
            return; // 已是最高级别
        }

        QueryWrapper<EngineerLevelConfigEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("level", newLevel);
        EngineerLevelConfigEntity newLevelConfig = levelConfigMapper.selectOne(wrapper);

        // 记录变更
        LevelChangeRecordEntity record = new LevelChangeRecordEntity();
        record.setEngineerId(engineer.getId());
        record.setOldLevel(oldLevel);
        record.setNewLevel(newLevel);
        record.setOldSalary(engineer.getCurrentSalary());
        record.setNewSalary(newLevelConfig.getBaseSalary());
        record.setChangeType("即时升级");
        record.setChangeReason("项目评分≥90且为越级项目");
        record.setTriggerProjectId(assignment.getId());
        record.setChangeDate(LocalDate.now());
        record.setEffectiveDate(getNextMonthFirstDay());

        levelChangeMapper.insert(record);

        // 更新工程师信息
        engineer.setCurrentLevel(newLevel);
        engineer.setCurrentSalary(newLevelConfig.getBaseSalary());
        engineerMapper.updateById(engineer);
    }

    /**
     * 季度评估
     */
    @Transactional
    public void quarterlyEvaluation(int year, int quarter) {
        List<EngineerEntity> engineers = engineerMapper.selectList(
                new QueryWrapper<EngineerEntity>().eq("status", 1)
        );

        for (EngineerEntity engineer : engineers) {
            evaluateEngineerQuarterly(engineer, year, quarter);
        }
    }

    /**
     * 评估单个工程师的季度表现
     */
    private void evaluateEngineerQuarterly(EngineerEntity engineer, int year, int quarter) {
        LocalDate quarterStart = LocalDate.of(year, (quarter - 1) * 3 + 1, 1);
        LocalDate quarterEnd = quarterStart.plusMonths(3).minusDays(1);

        // 获取季度内完成的项目
        QueryWrapper<ProjectAssignmentEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("engineer_id", engineer.getId())
                .eq("status", "2") //已完成
                .between("completion_date", quarterStart, quarterEnd);

        List<ProjectAssignmentEntity> assignments = assignmentMapper.selectList(wrapper);

        if (assignments.isEmpty()) {
            return;
        }

        // 计算季度平均分
        BigDecimal totalScore = assignments.stream()
                .map(ProjectAssignmentEntity::getTotalScore)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal averageScore = totalScore.divide(
                BigDecimal.valueOf(assignments.size()), 2, RoundingMode.HALF_UP
        );

        // 检查是否有困难项目
        boolean hasDifficultProject = checkDifficultProjects(assignments);

        // 记录季度评分
        QuarterlyScoreEntity quarterlyScore = new QuarterlyScoreEntity();
        quarterlyScore.setEngineerId(engineer.getId());
        quarterlyScore.setYear(year);
        quarterlyScore.setQuarter(quarter);
        quarterlyScore.setQuarterStr(year + "Q" + quarter);
        quarterlyScore.setTotalProjects(assignments.size());
        quarterlyScore.setCompletedProjects(assignments.size());
        quarterlyScore.setAverageScore(averageScore);
        quarterlyScore.setHasDifficultProject(hasDifficultProject ? 1 : 0);
        quarterlyScore.setIsEvaluated(1);

        quarterlyScoreMapper.insert(quarterlyScore);

        // 检查是否需要降级
        String reason = checkDemotion(engineer, quarterlyScore);
    }

    /**
     * 检查困难项目
     */
    private boolean checkDifficultProjects(List<ProjectAssignmentEntity> assignments) {
        for (ProjectAssignmentEntity assignment : assignments) {
            QueryWrapper<ProjectEntity> wrapper = new QueryWrapper<>();
            wrapper.eq("id", assignment.getProjectId());
            ProjectEntity project = (ProjectEntity) projectMapper.selectOne(wrapper);

            if ("困难".equals(project.getDifficultyName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查降级
     */
    private String checkDemotion(EngineerEntity engineer, QuarterlyScoreEntity quarterlyScore) {
        boolean shouldDemote = false;
        String reason = "";

        // 条件1：季度平均分低于60
        if (quarterlyScore.getAverageScore().compareTo(BigDecimal.valueOf(60)) < 0) {
            shouldDemote = true;
            reason = "季度平均分低于60分";
        }

        // 条件2：K1工程师连续两季度未接困难项目
        if (ProjectConstants.ENGINEER_LEVEL_K1.equals(engineer.getCurrentLevel()) && quarterlyScore.getHasDifficultProject() == 0) {
            if (checkConsecutiveNoDifficultProjects(engineer.getId(), quarterlyScore.getYear(), quarterlyScore.getQuarter())) {
                shouldDemote = true;
                reason = "K1工程师连续两季度未接困难项目";
            }
        }

        if (shouldDemote) {
            demoteEngineer(engineer, quarterlyScore, reason);
        }
        return reason;
    }

    /**
     * 检查连续两季度未接困难项目
     */
    private boolean checkConsecutiveNoDifficultProjects(Long engineerId, int year, int quarter) {
        // 获取前一季度记录
        int prevYear = year;
        int prevQuarter = quarter - 1;
        if (prevQuarter == 0) {
            prevYear = year - 1;
            prevQuarter = 4;
        }

        QueryWrapper<QuarterlyScoreEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("engineer_id", engineerId)
                .eq("year", prevYear)
                .eq("quarter", prevQuarter);

        QuarterlyScoreEntity prevQuarterlyScore = quarterlyScoreMapper.selectOne(wrapper);

        return prevQuarterlyScore != null && prevQuarterlyScore.getHasDifficultProject() == 0;
    }

    /**
     * 降级工程师
     */
    private void demoteEngineer(EngineerEntity engineer, QuarterlyScoreEntity quarterlyScore, String reason) {
        String oldLevel = engineer.getCurrentLevel();
        String newLevel = getPrevLevel(oldLevel);

        if (newLevel == null) {
            return; // 已是最低级别
        }

        QueryWrapper<EngineerLevelConfigEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("level", newLevel);
        EngineerLevelConfigEntity newLevelConfig = levelConfigMapper.selectOne(wrapper);

        // 记录变更
        LevelChangeRecordEntity record = new LevelChangeRecordEntity();
        record.setEngineerId(engineer.getId());
        record.setOldLevel(oldLevel);
        record.setNewLevel(newLevel);
        record.setOldSalary(engineer.getCurrentSalary());
        record.setNewSalary(newLevelConfig.getBaseSalary());
        record.setChangeType("季度降级");
        record.setChangeReason(reason);
        record.setQuarter(quarterlyScore.getQuarterStr());
        record.setQuarterlyScore(quarterlyScore.getAverageScore());
        record.setChangeDate(LocalDate.now());
        record.setEffectiveDate(getNextMonthFirstDay());

        levelChangeMapper.insert(record);

        // 更新工程师信息
        engineer.setCurrentLevel(newLevel);
        engineer.setCurrentSalary(newLevelConfig.getBaseSalary());
        engineerMapper.updateById(engineer);
    }

    /**
     * 获取下一个职级
     */
    private String getNextLevel(String currentLevel) {
        switch (currentLevel) {
            case ProjectConstants.ENGINEER_LEVEL_K3: return ProjectConstants.ENGINEER_LEVEL_K2;
            case ProjectConstants.ENGINEER_LEVEL_K2: return ProjectConstants.ENGINEER_LEVEL_K1;
            case ProjectConstants.ENGINEER_LEVEL_K1: return null;
            default: return null;
        }
    }

    /**
     * 获取上一个职级
     */
    private String getPrevLevel(String currentLevel) {
        switch (currentLevel) {
            case ProjectConstants.ENGINEER_LEVEL_K1: return ProjectConstants.ENGINEER_LEVEL_K2;
            case ProjectConstants.ENGINEER_LEVEL_K2: return ProjectConstants.ENGINEER_LEVEL_K3;
            case ProjectConstants.ENGINEER_LEVEL_K3: return null;
            default: return null;
        }
    }

    /**
     * 获取下月第一天
     */
    private LocalDate getNextMonthFirstDay() {
        return LocalDate.now().plusMonths(1).withDayOfMonth(1);
    }
}
